package cn.melonlib.graphql.model.scalars;

import cn.hutool.core.util.ClassUtil;
import graphql.language.FloatValue;
import graphql.language.IntValue;
import graphql.language.Value;
import graphql.schema.Coercing;
import graphql.schema.CoercingParseLiteralException;
import graphql.schema.CoercingParseValueException;
import graphql.schema.CoercingSerializeException;

import java.math.BigDecimal;
import java.math.BigInteger;

import static graphql.Assert.assertNotNull;

public class GraphQLBigDecimal implements Coercing<BigDecimal,BigDecimal> {


    private BigDecimal convertImpl(Object input) {
        if(input instanceof BigDecimal number){
            return number;
        }else if(input instanceof Number number){
            return BigDecimal.valueOf(number.doubleValue());
        } else if (input instanceof CharSequence numString) {
            BigDecimal value;
            try {
                value = new BigDecimal(numString.toString());
            } catch (NumberFormatException e) {
                return null;
            }
            try {
                return value;
            } catch (ArithmeticException e) {
                return null;
            }
        } else {
            return null;
        }
    }

    @Override
    public BigDecimal serialize(Object input) {
        BigDecimal result = convertImpl(input);
        if (result == null) {
            throw new CoercingSerializeException(
                    "Expected type 'Int' but was '" + ClassUtil.getClassName(input,true) + "'."
            );
        }
        return result;
    }

    @Override
    public BigDecimal parseValue(Object input) {
        BigDecimal result = convertImpl(input);
        if (result == null) {
            throw new CoercingParseValueException(
                    "Expected type 'Int' but was '" + ClassUtil.getClassName(input,true) + "'."
            );
        }
        return result;
    }

    @Override
    public BigDecimal parseLiteral(Object input) {
        if (!(input instanceof IntValue)) {
            throw new CoercingParseLiteralException(
                    "Expected AST type 'IntValue' but was '" + ClassUtil.getClassName(input,true) + "'."
            );
        }
        BigDecimal value = ((FloatValue) input).getValue();
        return value;
    }

    @Override
    public Value valueToLiteral(Object input) {
        BigDecimal result = assertNotNull(convertImpl(input));
        return FloatValue.newFloatValue(result).build();
    }
}
